package com.cml.rpc.client;

import com.cml.rpc.publicpojo.RpcRequest;
import com.cml.rpc.publicpojo.RpcResponse;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 动态代理接口方法，目的：是代理对象待用方法时，封装request数，然后发送给服务端，接收响应，返回响应
 * @author cml
 * @create 2021/7/20 15:04
 */
public class ClientProxy implements InvocationHandler {
    private String host;
    private Integer port;

    public ClientProxy(String host, Integer port) {
        this.host = host;
        this.port = port;
    }

    /**
     * 使用jdk动态代理，代理对象调用方法，会经过此方法增强，反射获取request对象
     * @param proxy
     * @param method
     * @param args
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 通过反射获取接口信息
        String interfaceName = method.getDeclaringClass().getName();
        String methodName = method.getName();
        Class<?>[] paramTypes = method.getParameterTypes();
        // 封装成rpcRequest，builder使用了lombok的builder注解
        RpcRequest rpcRequest = RpcRequest.builder().interfaceName(interfaceName)
                .methodName(methodName).params(args).paramTypes(paramTypes).build();
        // 发送数据
        RpcResponse rpcResponse = IOClient.sendRequest(host, port, rpcRequest);
        System.out.println("客户端接收服务端响应数据rpcResponse = " + rpcResponse);
        return rpcResponse.getData();
    }

    /**
     * 获取代对象，只有通过代理对象调用方法，才能是方法加强
     * @param clazz
     * @param <T>
     * @return
     */
    <T>T getProxy(Class<T> clazz) {
        /*
        * 关于newProxyInstance 三个参数
        * load：用那个类加载器去加载代理对象
        * interface：动态代理类需要实现的接口
        * h: invocationHandler类型 动态代理方法在执行时回调用里面invoke方法。此处写的this是因为本类实现了invocationHandler接口
        */
        Object proxyInstance = Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, this);
        return (T)proxyInstance;
    }
}
